﻿using SharpDX.Direct3D11;
using System.Windows.Forms;
using SharpDX;
using SharpDX.D3DCompiler;
using SharpDX.DXGI;
using SharpDX.Windows;
using Device = SharpDX.Direct3D11.Device;
using Resource = SharpDX.Direct3D11.Resource;
using System.Runtime.InteropServices;
using SharpDX.Direct3D;

namespace Engine
{
    public class GSSprite : System.IDisposable
    {
        Buffer Vertexs;
        VertexBufferBinding binding;

        int VertexsCount, BytesPerVertex;

        ShaderConstants constants;
        Buffer constantsBuffer;

        public EffectContainer EEEM;
        TextureContainer TexCont;
        

        public DVector3 Position;

        #region IDisposable
        ~GSSprite()
        {
            Dispose();
        }
        public void Dispose()
        {
            constantsBuffer.Dispose();
            EEEM.Dispose();
            TexCont.Dispose();
         }
        #endregion

        public GSSprite(Device device, DVector3 Position)
        {
            //float3 Position //12
            //half2 Size //16
            //half4 AABBTexCoord //24
            //half4 AditiveColor //32
            InputElement[] elements = new[] {
                new InputElement("POSITION", 0, Format.R32G32B32_Float, 0, 0),
                new InputElement("TEXCOORD", 0, Format.R16G16_Float, 12, 0),
                new InputElement("TEXCOORD", 1, Format.R16G16B16A16_Float, 16, 0),
                new InputElement("TEXCOORD", 2, Format.R16G16B16A16_Float, 24, 0),
            };


            BytesPerVertex = 32;
            VertexsCount = 1;

            var vertices = new DataStream(BytesPerVertex * VertexsCount, true, true);

            vertices.Write(Conversion.ToVector3(Position));
            vertices.Write(new Half2(10, 10));
            vertices.Write(new Half4(0, 0, 1, 1));
            vertices.Write(new Half4(1, 0, 0, 1));
            vertices.Position = 0;

            Vertexs = new Buffer(device, vertices, BytesPerVertex * VertexsCount, ResourceUsage.Dynamic, BindFlags.VertexBuffer, CpuAccessFlags.Write, ResourceOptionFlags.None, 0);
            binding = new VertexBufferBinding(Vertexs, BytesPerVertex, 0);
            vertices.Dispose();

            this.Position = Position;
            EEEM = ContentManager.LoadEffect("Content/Shaders/GSSprite", elements);
            TexCont = ContentManager.LoadTexture2D("Content/Textures/Particl");
            // Подготовка константного буффера
            BufferDescription bd = new BufferDescription();
            bd.SizeInBytes = Marshal.SizeOf(typeof(ShaderConstants));
            bd.Usage = ResourceUsage.Dynamic;
            bd.BindFlags = BindFlags.ConstantBuffer;
            bd.CpuAccessFlags = CpuAccessFlags.Write;
            bd.OptionFlags = ResourceOptionFlags.None;
            bd.StructureByteStride = 0;

            constantsBuffer = new Buffer(device, bd);
            constants = new ShaderConstants();
        }

        public void Render(Device device, EEDCamera Camera, ShaderResourceView DepthMap)
        {
            var vertices = new DataStream(BytesPerVertex * VertexsCount, true, true);

            vertices.Write(Conversion.ToVector3(Position - Camera.position));
            vertices.Write(new Half2(50, 50));
            vertices.Write(new Half4(0, 0, 1, 1));
            vertices.Write(new Half4(0, 0, 1, 1));
            vertices.Position = 0;

            DataStream stream;
            device.ImmediateContext.MapSubresource(Vertexs, MapMode.WriteDiscard, SharpDX.Direct3D11.MapFlags.None, out stream);
            stream.Position = 0;
            stream.WriteRange(vertices.DataPointer, vertices.Length);
            device.ImmediateContext.UnmapSubresource(Vertexs, 0);
            stream.Dispose();
            vertices.Dispose();
            binding = new VertexBufferBinding(Vertexs, BytesPerVertex, 0);

            constants.FarPlane = new Vector4(Camera.farClip,0,0,0);
            constants.VP = Matrix.Transpose(Camera.viewProjectionMatrix);
            var dataBox = ModelViewer.Program.device.ImmediateContext.MapSubresource(constantsBuffer, 0, MapMode.WriteDiscard, SharpDX.Direct3D11.MapFlags.None);
            Utilities.Write(dataBox.DataPointer, ref constants);
            ModelViewer.Program.device.ImmediateContext.UnmapSubresource(constantsBuffer, 0);

            device.ImmediateContext.InputAssembler.InputLayout = EEEM.layout;
            device.ImmediateContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.PointList;
            device.ImmediateContext.InputAssembler.SetVertexBuffers(0, binding);

            EEEM.renderTechniques[0].GetPassByIndex(0).Apply(device.ImmediateContext);

            device.ImmediateContext.PixelShader.SetShaderResource(0, TexCont.TextureResource);
            device.ImmediateContext.PixelShader.SetSampler(0, DrawHelper.SamplAnsWrapMip);

            //device.ImmediateContext.PixelShader.SetShaderResource(1, DepthMap);
            device.ImmediateContext.VertexShader.SetShaderResource(1, DepthMap);

            //Константный буффер передается шейдерам
            device.ImmediateContext.VertexShader.SetConstantBuffer(0, constantsBuffer);
            //device.ImmediateContext.PixelShader.SetConstantBuffer(0, constantsBuffer);

            device.ImmediateContext.Draw(VertexsCount, 0);

        }

        private struct ShaderConstants
        {
            public Matrix VP;
            public Vector4 FarPlane;
        }

    }
}
